package yartiss.engine.simulation.system.taskset.generation;

import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;

import yartiss.engine.simulation.io.ITaskElementVisitor;
import yartiss.engine.simulation.io.TasksetWriter;
import yartiss.engine.simulation.io.TextWriter;
import yartiss.engine.simulation.io.XmlFileWriter;
import yartiss.engine.simulation.system.ITask;
import yartiss.engine.simulation.system.SystemMetrics;
import yartiss.engine.simulation.system.taskset.generation.task.DefaultTaskGenerator;
import yartiss.engine.simulation.system.taskset.generation.task.GraphTaskGenerator;
import yartiss.framework.concurrency.Consumer;
import yartiss.framework.concurrency.IElementConsumedListener;
import yartiss.framework.concurrency.Producer;
import yartiss.framework.concurrency.QueueEntry;


public class SystemsGenerator {

	private static int counter = 0;
	private static boolean finished;

	/**
	 * Generates tasksets with specific types of task
	 * 
	 * @param count
	 *            number of tasksets
	 * @param nbProc
	 *            number of processors
	 * @param nbTasks
	 *            number of tasks in each taskset
	 * @param pr
	 *            power rate
	 * @param emax
	 *            maximum energy
	 * @param file
	 *            output file
	 * @param taskType
	 *            type of task (simple, graph, ...)
	 * 
	 * @throws IOException
	 * @throws Exception
	 */
	public static void generateTaskSets(final int count, int nbProc,
			int nbTasks, final int pr, final long emax, String file,
			final String taskType) throws Exception {
		finished = false;
		boolean energy;
		double padUnit = 0.05, pad = 0;
		long n, nb;
		do {
			pad += padUnit;
			n = Math.round(1 / pad);
			nb = count / (n * n);
		} while (nb <= 0);
		if (pad >= 1) {
			pad = 0.9;
			n = 1;
			nb = count;
		}
		// System.out.println(n+"*"+n+"*"+nb+"  pad="+pad);
		counter = 1;
		// final TasksetWriter writer = new TasksetWriter(file);
		// final ITaskElementVisitor writer = new TextWriter(file, count,
		// nbTasks);
		final ITaskElementVisitor writer = new XmlFileWriter(file, count,
				nbTasks);
		BlockingQueue<QueueEntry<ITask[]>> queue = new LinkedBlockingQueue<QueueEntry<ITask[]>>(
				100000);

		final Consumer<ITask[]> consumer = new Consumer<ITask[]>(queue,
				new IElementConsumedListener<ITask[]>() {
					@Override
					public void consume(ITask[] tasks) {
						try {
							if (tasks.length < 1 || counter > count) {
								System.out.println("hehe");
								return;
							}

							double u = Math.round(SystemMetrics
									.utilisation(Arrays.asList(tasks)) * 1000) / 1000.0d;
							double ue = Math.round(SystemMetrics
									.energyUtilization(Arrays.asList(tasks), pr) * 1000) / 1000.0d;

							System.out.println(counter + "\t: U=" + u + "\tUe="
									+ ue);
							// writer.writeTaskSet(tasks, pr);
							// writer.visitTaskset(Arrays.asList(tasks), pr);
							writer.visitTaskset(tasks, pr);
							// System.out.print("\033[H"+(counter*100)/count+"          %");
							if (counter >= count) {
								finished = true;
								System.out.println("writer closed!");
								writer.close();
							}
							counter++;

						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				});
		consumer.start();
		do {
			final Producer<ITask[]> producer = new Producer<ITask[]>(queue);
			for (int i = 1; i <= n; i++) {
				for (int j = 1; j <= n; j++) {
					if (i * pad < 1 && j * pad < 1) {

						ITaskGenerator generator;
						if (taskType.toLowerCase().equals("simple")) {
							generator = new DefaultTaskGenerator();
							energy = true;
						} else if (taskType.toLowerCase().equals("graph")) {
							System.out.println("prodiucer:; graph");
							generator = new GraphTaskGenerator();
							energy = false;
						} else
							throw new IllegalArgumentException("Task model ("
									+ taskType + ") doesn't exist...");

						final ITaskSetGenerator taskSetGenerator = new UUniFastDiscardTaskSetGen(
								generator, nbTasks, nbProc, i * pad, j * pad,
								pr, emax, 0, false, energy);
						for (int k = 0; k < nb; k++) {
							producer.produce(new Callable<ITask[]>() {
								@Override
								public ITask[] call() throws Exception {

									if (finished) {
										return null;
									}

									ITask[] tasks = taskSetGenerator.generate();
									if (tasks == null) {
										System.out.println("NULL");
										return new ITask[] {};
									}
									for (ITask iTask : tasks) {
										System.out.println("ITASK: "
												+ iTask.toString());
									}
									return tasks;
								}
							});
						}
					}
				}
			}
			Thread.sleep(1000);
			producer.awaitTermination();
		} while (counter < count);
		queue.put(new QueueEntry<ITask[]>(null));
		System.out.println("fini");
	}

	public static void generateTaskSets(int count, int nbProc, int nbTasks,
			double U, double Ue, int pr, long emax, String file, String taskType)
			throws IOException {
		ITaskSetGenerator taskSetGenerator = null;
		// TasksetWriter writer = new TasksetWriter(file);
		taskSetGenerator = new UUniFastDiscardTaskSetGen(
				new DefaultTaskGenerator(), nbTasks, nbProc, U, Ue, pr, emax,
				0, false, true);
		for (int i = 0; i < count; i++) {
			ITask[] tasks = taskSetGenerator.generate();
			for (ITask task : tasks) {
				System.out.println(task);
			}
			System.out
					.println(i
							+ " ## U="
							+ SystemMetrics.utilisation(Arrays.asList(tasks))
							+ "##Ue="
							+ SystemMetrics.energyUtilization(
									Arrays.asList(tasks), pr));
			TextWriter writer = new TextWriter(file, count, nbTasks);
			// writer.visitTaskset(Arrays.asList(tasks), pr);
			writer.visitTaskset(tasks, pr);
			// writer.writeTaskSet(tasks, pr);
		}
		// writer.close();
	}

	public static void oldGenerate(Class<?> clazz) throws IOException {
		String setsDest = "systems/old_";
		String setsSrc = "/resources/tasks_sets";
		String energySrc = "/resources/energy_";

		long[] pr = new long[] { 10, 15, 20, 25, 30, 35 };
		long[] emaxs = new long[] { 200, 400 };
		for (int i = 0; i < emaxs.length; i++) {
			for (int j = 0; j < pr.length; j++) {
				TasksetWriter writer = new TasksetWriter(setsDest + emaxs[i]
						+ "_" + pr[j] + ".txt");
				FileTaskSetGenerator generator = new FileTaskSetGenerator(
						clazz.getResourceAsStream(setsSrc),
						clazz.getResourceAsStream(energySrc + emaxs[i] + "_"
								+ pr[j] + ".txt"), pr[j]);
				int count = 30;// generator.getSetsCount();
				for (int k = 0; k < count; k++) {
					writer.writeTaskSet(generator.generate(), (int) pr[j]);
				}
				writer.close();
			}
		}
	}

	/*
	public static void main(String[] args) throws Exception {
		int nbSystems = 10, pr = 35;
		long emax = 400;
		int nbTasks = 6;
		// String taskType = "simple";
		String taskType = "graph";
		try {
			nbSystems = Integer.parseInt(args[0]);
		} catch (Exception e) {
			nbSystems = 100;
		}

		// String taskSetsSource = "results/" + nbSystems + "_systems_pr_" + pr;

		
		  String taskSetsSource = nbSystems + taskType + "_systems_pr_" +
		 pr+".xml"; generateTaskSets(nbSystems, 2, nbTasks, pr, emax,
		  taskSetsSource, taskType);
		 
		// XmlFileReader reader = new XmlFileReader(taskSetsSource);
		// reader.readTasksets();

		XmlFromFileWriter writer = new XmlFromFileWriter(
				SystemsGenerator.class
						.getResourceAsStream("/resources/EDF_test1"),
				new FileOutputStream("EDF_test1.xml"));
	}*/

}
